#include "header.h"
#include "fraglist.h"
#include <unistd.h>

/* Gibt die größe einer Datei in Bytes zurück
 * IN:   Adresse auf geöffnete Datei (FILE *)
 * RET:  >0 = OK, -1=NULL übergeben
 */
int get_filesize( char *filename ){
	int i;
	FILE *file=NULL;
	file = fopen(filename, "rb"); 

	if(NULL == file){
		if(debug) printf("D get_filesize():\n   > Datei existiert nicht!\n");
		return -1;
	}
		for(i=0; fgetc(file) != EOF; i++ );
	//fseek(file,0,0); // fseek(*datei, um wieviel verschieben, von wo an verschieben
	fclose(file);
	return i;
}

//gibt eine prüfsumme zurück, wollte corni machen
unsigned int checksum(frag *_frag){
	return 0;
}

/* initialisiert ein element vom typ frag
 * IN:   zeichenkette (char *), länge der kette (unsigned int), index nr. des elementes (unsigned int)
 * RET:  adresse auf frag struktur (frag *)/ NULL im fehlerfall
 * NOTE: 
 */
frag *frag_create(char *segment, unsigned int seglen, unsigned int index){
	int i=0;
	frag *_frag=malloc(sizeof(frag));
	if(!_frag){
		if(debug) printf("D frag_create():\n   > Fataler fehler, kein Haupspeicher mehr");
		return NULL;
	}
	_frag->seglen=seglen;

//	_frag->segment=(char*)malloc(sizeof(char*)*seglen);
//	if(!(_frag->segment)){
//		if(debug) printf("D frag_create():\n   > Fataler fehler, kein Haupspeicher mehr");
//		return NULL;
//	}
	
	for(i=0;i<seglen;i++)
		_frag->segment[i]=segment[i];

	_frag->index = index;
	_frag->checksum = checksum(_frag); //achtung, sollte wirklich erst zum schluss kommen
	return _frag;
}

//initialisiert eine neue liste
fraglist *fraglist_init(void){
	fraglist *fl=(fraglist *)malloc(sizeof(fraglist));
/*	if(!fl){
		if(debug) printf("D fraglist_init():\n   > Fataler Fehler! Nicht genügend Hauptspeicher!\n");
		return NULL;
	}
*/	fl->first=fl;
	fl->index=0;
	fl->count=0;
	fl->next=NULL;
	
	fl->_frag = NULL;
//fl->_frag->index = 0;

	return fl;
}

//fügt ein neues element an
int fraglist_add(fraglist *fl, frag *_frag){
	if(!fl){
		if(debug) printf("D fraglist_add()\n   > Fehler! Fraglist existiert nicht! Erstelle neue\n");
		fl=fraglist_init();
	}
	
	//wird benötigt damit das 0. element der liste genutzt werden kann
	if( fl->_frag ){
		for(;fl->next!=NULL;fl=fl->next);
		fl->next=malloc(sizeof(fraglist ));
		if(!(fl->next)){
			if(debug) printf("D fraglist_add():\n   > Fataler Fehler! Nicht genügend speicher für ein neues element!\n");
			return -1;
		}
		fl->next->first=fl->first;
		fl->next->next=NULL;
		fl->next->_frag=_frag;
		fl->first->count=fl->first->count+1;
		fl->next->index=fl->first->count;
		return 0;
	}
	fl->next=NULL;
	fl->_frag=_frag;
	fl->count=0;
	fl->index=0;
	
	return 0;
}

/* löscht ein element aus der liste
 * IN:    adresse auf listenelement (fraglist *), index nr des zu löschenden elementes (unsigned int)
 * RET:   erstes element aus der liste! WICHTIG! Deswegen beim aufruf immer _frag=fraglist_del();
 * NOTE:  
*/
fraglist *fraglist_del(fraglist *this, unsigned int index){
	fraglist *temp=NULL, *first=this;
	
	//0. option, keine adresse übergeben
	if(NULL == this){
		if(debug) printf("D fraglist_del():\n   > Keine adresse auf Fragment übergeben!\n");
		return NULL;
	}

	//1. option, es wurde nicht das erste element der liste übergeben.
	if( first != first->first){
		return fraglist_del(first->first, index);
		
	}
	//2. option, löschen des 0. elementes
	if( index == this->index ){
		if(debug) printf("D fraglist_del():\n   > Lösche Fragment mit Index: %d\n", this->index);
		temp=this;
		//this=this->next;
		//falls nicht das erste element der liste übergeben wurde
		if(first!=this->first){
			for(this=this->first;this->next != temp; this=this->next);
			this->next = this->next->next;
		}
		//falls das erste element der liste zu löschen ist müssen alle first zeiger der liste neu gesetzt werden
		else{
			for(this=first->first;this != NULL; this=this->next)
				this->first=first->next;
			//	printf("ccc %p, %p\n",this, first->next);
		}
		//wichtig falls mal ein segment falsch oder gar nicht initialisiert wurde
//		if(temp->_frag){
//			if( 0 != temp->_frag->seglen )
//				free(temp->_frag->segment);
//		}
		first=first->next;
		free(temp);
		temp=NULL;
		//printf("\nDDD %p\n", first->next);
		return first;
	}		

	//3. option, elemente aus der mitte wird gelöscht
	for(; NULL != this->next; this=this->next){
		if( index == this->next->index ){
			if(debug) printf("D fraglist_del():\n   > Lösche Fragment mit Index: %d\n", this->next->index);
			temp=this->next; 
			//falls es das letzte element ist existiert this->next->next nicht
			if(!(this->next)){
				this->next=this->next->next;
//				if(temp->_frag){
//					if( 0 != temp->_frag->seglen )
//						free(temp->_frag->segment);
//				}
			}else
				this->next=NULL;
			free(temp);
			return first->first;
		}
	}
			
	//4. option, element existiert nicht
	if(debug) printf("D fraglist_del():\n   > Fragment mit Index: %d nicht gefunden!\n", index);
	return first;
}

//löscht das letzte element
//hat noch einen fehler
fraglist *fraglist_del_last(fraglist *this){
	fraglist *first=this, *temp=NULL;
	
	//0. option, keine adresse übergeben
	if(NULL == this){
		if(debug) printf("D fraglist_del_last():\n   > Keine adresse auf Fragment übergeben!\n");
		return NULL;
	}

	//1. option, es wurde nicht das erste element der liste übergeben.
	if( first != first->first){
		return fraglist_del_last(first->first);
	}

	//2. option, elemente aus der mitte wird gelöscht
	for(temp=this; NULL != this->next; temp=this, this=this->next);
	if(debug) printf("D fraglist_del_last():\n   > Lösche Fragment mit Index: %d\n", this->index);
	
	//falls das letzte element gelöscht wird gib 0 zurück
	if(first->first==temp){	
		free(temp);
		return NULL;
	}

	temp->next=NULL;
	temp=this;
//	if(temp->_frag){
//		if( NULL != temp->_frag)
//			free(temp->_frag->segment);
//	}
	free(temp);
	return first->first;
}

//löscht die gesamte liste
fraglist *fraglist_clear(fraglist *this){
	fraglist *temp=NULL;
	
	//0. option, keine adresse übergeben
	if(NULL == this){
		if(debug) printf("D fraglist_del():\n   > Keine adresse auf Fragment übergeben!\n");
		return NULL;
	}

	//1. option, es wurde nicht das erste element der liste übergeben.
	if( this != this->first){
		return fraglist_clear(this->first);	
	}

	//komplette liste löschen
	for(temp=this;this != NULL; temp=this){
		if(debug) printf("D fraglist_del_last():\n   > Lösche Fragment mit Index: %d\n", this->index);
		this=this->next;
		if(temp->_frag){
			//if( 0 != temp->_frag->seglen )
				if( NULL != temp->_frag);
//				free(temp->_frag->segment);
		}
		free(temp);
	}
	return NULL;
}

//ermittelt die länge der liste
unsigned int fraglist_len(fraglist *this){
	unsigned int i=0;
	
	//0. option, keine adresse übergeben
	if(NULL == this){
		if(debug) printf("D fraglist_del():\n   > Keine adresse auf Fragment übergeben!\n");
		return i;
	}

	//geht die liste durch 
	for(this=this->first; this->next != NULL; this=this->next, i++);
	return i;
}

/* gibt die fragmentenliste aus
 * IN:   Adresse auf liste
 * RET:  0=OK, -1=NULL als adresse übergeben
 * NOTE: angenehm zum testen und entkäfern
 */
int fraglist_out(fraglist *fl){
	int i=0;
	
	if(NULL == fl){
		if(debug) printf("D fraglist_out():\n   > Keine adresse auf Fragment übergeben!\n");
		return -1;
	}
	
	printf("\nAUSGABE DER FRAGMENTLISTE!\n");
	for(; NULL != fl;fl=fl->next){
		printf("\n---------------%d. Fragment---------------\n",fl->index);
		if(fl->_frag){
			printf("\nSegmentlänge: %d\nSegment Inhalt:\n\"", fl->_frag->seglen);
			for(i=0; i < (fl->_frag->seglen); i++) 
				printf("%c",fl->_frag->segment[i]);
			printf("\"");
		}else
			printf("Listenelement enthält kein Fragment!");
	}
	printf("\nENDE DER FRAGMENTLISTE!\n");
	return 0;
}


int main(void){
	int i=0, j=0, filesize=0, bytecount=0, seglen=SEG_SIZ;
	char segment[SEG_SIZ], c='\0';
    FILE *file=NULL;
	fraglist *fl=NULL; //die liste mit dem datei inhalt
    frag f;	//das start fragment mit datei namen
	char *filename=DAT;

	//0. initialisieren der liste
    fl=fraglist_init();
   
	//1. Datei öffnen
    file = fopen(filename, "r"); //rb = als byte einlesen, read byte

    //2. erstelle start frag mit dateinamen und sende es an server
	// nochmal über bessere lösung bezüglich des längentechnisch eingeschränkten datei namens nachdenken
    f.seglen=strnlen(filename,SEG_SIZ);
    strncpy(f.segment, filename, SEG_SIZ);
    f.checksum=checksum(&f);
    f.index=0;

    //2.1. startet das netzwerk
//		if( -1 == network_start_client(&to_server, ip, port) ){
//		printf(" Fehler! Netzwerk konnte nicht gestartet werden!\n");
//		return;
//	}
	
	//2.2 sendet das erste frame mit dem dateinamen
//	rc=sendto(to_server.socket,&f,sizeof(f),0,(SOCKADDR*)&(to_server.saddr),sizeof(SOCKADDR_IN6));
	//2.3 empfängt das ack
	//rc=recvfrom(to_server.socket,&f,sizeof(f),0,&remoteAddr,&(to_server.addrlen));
	
	filesize=get_filesize(filename);
		
		for(j=0; (c!=EOF); j++){
		//da im letzten fragment idr. nicht die ganze SEG_SIZ benötigt wird, diese if
		
		if(filesize-bytecount+1 <= SEG_SIZ)
				seglen=filesize-bytecount+1;
        
		//befüllt das aktuelle segment mit den n zeichen aus der datei
		for(i=0; i < seglen; i++, bytecount++){
			c=fgetc(file);
			if( EOF == c) break;                                                                            //oder muss das EOF flag mit übertragen werden?
			segment[i]=c;
		}
		segment[i+1]='\0';
		        
		//fügt das segment an die liste an
		fraglist_add(fl, frag_create(segment, seglen, fl->count));
		fraglist_out(fl);
		fl=fraglist_del(fl, fl->count);
		fl=fl?fl:fraglist_init(); //falls die liste leer ist, initialisiere sie neu
		
				
		//falls das letzte element gelöscht wurde, initialisiere die liste neu
		//fl=fl?fl:fraglist_init();
		debug?printf("\nD: sendfile()\n   > Sende Fragmentnr: %d\nD: Bereits %d/%d Byte übertragen\n", fl->index, bytecount, filesize):0;
        
		//strcpy(f.segment,segment);
		//f.seglen=seglen;
		//sendet fragment aus der liste
		//rc=sendto(to_server.socket,&f,sizeof(f),0,(SOCKADDR*)&(to_server.saddr),sizeof(SOCKADDR_IN6));
		//printf("list: %s\n",f.segment);
		//wartet wieder auf ack
		//rc=recvfrom(to_server.socket,&f,sizeof(f),0,&remoteAddr,&(to_server.addrlen));

		//fl=fl->next;
		//fraglist_out(fl);
		//falls ein ack zurück kommt fragment aus liste löschen
		//fl=fraglist_del_last(fl);
		//fl=fraglist_clear(fl);

//		if(rc==SOCKET_ERROR)
//			printf("Fehler: sendto, fehler code: %d\n",WSAGetLastError());
//		else
//		sleep(1);
			
			
			printf("%d Bytes gesendet!\n", bytecount);
	}

	return 0;
}
